﻿#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
#include<stdlib.h>

////malloc
//int main()
//{
//	//申请十个整型大小的空间
//	int* p = (int*)malloc(10 * sizeof(int));
//	if (p == NULL)
//	{
//		//空间开辟失败
//		perror("malloc");
//		return 1;//0表示正常返回，非0表示异常返回
//	}
//	////可以使用这40个字节的空间
//	//int i = 0;
//	//for (int i = 0; i < 10; i++)
//	//{
//	//	*(p + i) = i + 1;
//	//}
//	//释放
//	free(p);
//	p = NULL;
//
//	return 0;
//}

//int main()
//{
//	int* p = (int*)malloc(INT_MAX);
//	if (p == NULL)
//	{
//		//开辟空间失败
//		perror("malloc");
//		return 1;
//	}
//
//	return 0;
//}

//int main()
//{
//	int arr[10] = { 0 };//局部的数组，在栈上开辟空间
//	int* p = arr;
//
//	//...
//
//	//p指向的空间不是动态开辟的，所以不能动态释放
//	free(p);//err
//	p = NULL;
//
//	return 0;
//}

//int main()
//{
//	//...
//	int* p = NULL;
//	//...
//	free(p);//free里面的参数是NULL指针，则函数什么都不做
//
//	return 0;
//}

//calloc
//int main()
//{
//	//申请10个整型大小的空间
//	//int* p = (int*)malloc(10 * sizeof(int));
//	int* p = (int*)calloc(10, sizeof(int));
//	if (p == NULL)
//	{
//		perror("calloc");
//		return 1;
//	}
//	//使用空间
//	int i = 0;
//	for (i = 0; i < 10; i++)
//	{
//		printf("%d ", p[i]);//等价于*(p+i)
//	}
//	//释放
//	free(p);
//	p = NULL;
//
//	return 0;
//}

//realloc
//int main()
//{
//	//申请10个整型大小的空间
//	int* p = (int*)calloc(10, sizeof(int));
//	if (p == NULL)
//	{
//		perror("calloc");
//		return 1;
//	}
//	//使用空间
//	int i = 0;
//	for (i = 0; i < 10; i++)
//	{
//		printf("%d ", p[i]);//等价于*(p+i)
//	}
//
//	//...
//	//觉得空间不够，调整空间-希望变成20个整型空间
//	int* ptr = realloc(p, 20 * sizeof(int));
//	if (ptr != NULL)
//	{
//		p = ptr;
//	}
//	//使用
//	//...
//
//	//释放
//	free(p);
//	p = NULL;
//
//	return 0;
//}

//常见动态内存错误
//int main()
//{
//	int* p = (int*)malloc(10 * sizeof(int));
//
//	//1、对NULL指针的解引用操作
//	if (p == NULL)
//	{
//		perror("malloc");
//		return 1;
//	}
//
//	//使用
//	int i = 0;
//	//2、对动态开辟空间的越界访问
//	//for (i = 0; i < 40; i++)
//	for (i = 0; i < 10; i++)
//	{
//		p[i] = i + 1;//*(p+i) p是整型指针
//	}
//	free(p);
//	p = NULL;
//
//	return 0;
//}

//2、对非动态开辟内存使用free释放
//int main()
//{
//	int a = 10;
//	int* p = &a;
//	//...
//
//	free(p);//err
//	p = NULL;
//
//	return 0;
//}

//3、使用free释放一块动态开辟内存的一部分会报错
//int main()
//{
//	int* p = (int*)malloc(10 * sizeof(int));
//	if (p == NULL)
//	{
//		perror("malloc");
//		return 1;
//	}
//	//使用
//	int i = 0;
//	for (i = 0; i < 5; i++)
//	{
//		p[i] = i;
//	
//		//*p = i;
//		//p++;
//	}
//
//	free(p);
//	p = NULL;
//
//	return 0;
//}

//5、对同一块内存空间的多次释放
//int main()
//{
//	int* p = (int*)malloc(10 * sizeof(int));
//	if (p == NULL)
//	{
//		perror("malloc");
//		return 1;
//	}
//	//使用...
//	free(p);
//	p = NULL;
//	//如果此处p忘记置为NULL，再次free就相当于对野指针进行释放
//	//就会报错
//
//	//...
//	free(p);
//	p = NULL;
//
//	return 0;
//}

//6、动态内存开辟忘记释放，可能导致内存泄漏的问题
//void test()
//{
//	int flag = 1;
//	int* p = (int*)malloc(100);
//	if (p == NULL)
//	{
//		//
//		return 1;
//	}
//
//	//使用
//	if (flag)
//		return;//出函数无法对这块空间进行释放，应该把这块空间的地址返回
//
//	free(p);
//	p = NULL;
//}
//
//int main()
//{
//	test();
//
//	return 0;
//}

//int main()
//{
//	/*int* p = malloc(20);
//	realloc(p, 40);*/
//
//	//realloc不仅能调整空间，还可以申请空间
//	int* p = (int*)realloc(NULL, 40);//malloc(40)
//	if (p == NULL)
//	{
//
//	}
//
//	return 0;
//}

//经典笔试题
// 第一题
//#include<string.h>
//
//void GetMemory(char** p)
//{
//	*p = (char*)malloc(100);//存在内存泄漏
//}
//
//void Test(void)
//{
//	char* str = NULL;
//	//GetMemory(str);//传的值
//	GetMemory(&str);//正确写法，传地址
//	strcpy(str, "hello world");//对NULL指针解引用操作，程序就会崩溃
//	printf(str);
//
//	//malloc申请的空间，需要释放
//	free(str);
//	str = NULL;
//}
//
//int main()
//{
//	//char* p = "hehe\n";
//	//printf("hehe\n");//传的是字符串首字符的地址
//	//printf(p);
//
//	Test();
//	return 0;
//}

//#include<string.h>
//
//char* GetMemory()
//{
//	char* p = (char*)malloc(100);
//	return p;
//}
//
//void Test(void)
//{
//	char* str = NULL;
//	str = GetMemory();//传的值
//	strcpy(str, "hello world");
//	printf(str);
//
//	//malloc申请的空间，需要释放
//	free(str);
//	str = NULL;
//}
//
//int main()
//{
//	Test();
//	return 0;
//}

//第二题：返回栈空间地址问题
//char* GetMemory(void)
//{
//	char p[] = "hello world";//数组属于局部变量
//	//p是数组首元素的起始地址
//	return p;	//出函数，这块空间被销毁
//	//返回变量，但不能返回变量的地址
//}
//
//void Test(void)
//{
//	char* str = NULL;
//	str = GetMemory();//str接收的返回值是野指针
//	printf(str);//没有这块空间的使用权限，打印随机值
//}
//
//int main()
//{
//	Test();
//	return 0;
//}

//int test()
//{
//	int a = 10;
//	return a;
//}
//
//int main()
//{
//	int p = test();
//	printf("%d\n", p);//ok
//
//	return 0;
//}

//int* test()
//{
//	int a = 10;
//	return &a;
//}
//
//int main()
//{
//	int* p = test();//野指针
//	printf("%d\n", *p);
//
//	return 0;
//}

